#ifndef __ECHOSERVER_H__
#define __ECHOSERVER_H__

#include <unistd.h>
#include <iostream>
#include <nlohmann/json.hpp>
#include "../include/CacheManager.h"
#include "../include/Configuration.h"
#include "../include/Dictionary.h"
#include "../include/KeyRecommander.h"
#include "../include/Singleton.h"
#include "../include/SplitTool.h"
#include "../include/WebPageSearcher.h"
#include "../log/Logger.hpp"
#include "../include/TcpConnection.h"
#include "../include/TcpServer.h"
#include "../include/ThreadPool.h"
#include "../include/json.h"
// using json = nlohmann::json;
using std::cout;
using std::endl;

class MyTask {
   public:
    MyTask(const string& msg, const TcpConnectionPtr& con, int id)
        : _msg(msg), _con(con), _msgid(id) {}

    void process();

   private:
    int _msgid;
    string _msg;
    TcpConnectionPtr _con;
};

class EchoServer {
   public:
    EchoServer(size_t threadNum,
               size_t queSize,
               const string& ip,
               unsigned short port)
        : _pool(threadNum, queSize), _server(ip, port) {}

    ~EchoServer() {}

    void start() {
        Dictionary* ptr = Dictionary::getInstance();
        Configuration& pconf = Configuration::getInstance();
        map<string,string> confmap = pconf.getConfigMap();
        ptr->init(confmap.find("ENGLISH_DICT_PATH")->second, confmap.find("CHINESE_DICT_PATH")->second,
                  confmap.find("ENGLISH_INDEX_PATH")->second, confmap.find("CHINESE_INDEX_PATH")->second);

        shared_ptr<CacheManager> caches = Singleton<CacheManager>::GetInstance(4,64);
        caches->init();  

        _pool.start();  // 子线程会在TaskQueue中取Task，因为现在TaskQueue是空的，所以会调用pop阻塞

        // 将Tcp通信过程中的三个事件注册给了TcpServer，然后交给EventLoop，最后交给TcpConnection
        using namespace std::placeholders;
        _server.setAllCallback(std::bind(&EchoServer::onConnection, this, _1),
                               std::bind(&EchoServer::onMessage, this, _1),
                               std::bind(&EchoServer::onClose, this, _1));
        // 让服务器调用ready函数，使得服务器处于监听状态
        // 并且让Reactor/EventLoop进行循环监听(使用epoll_wait进行监听)
        // 监听的文件描述符包括三种：
        // 1、listenfd（有没有新的连接请求过来）
        // 2、evtfd,监听线程池与EventLoop通信的文件描述符,只要被监听，让EventLoop/Reactor
        // 将线程池处理之后的msg发送给客户端
        // 3、connfd，也就是Acceptor类调用accept函数的正确返回结果，如果有可读事件，
        // 就表明客户端发送了数据给了服务器，服务器就可以与客户端进行通信
        _server.start();
    }

    void stop() {
        _pool.stop();
        _server.stop();
    }

    // 连接建立
    void onConnection(const TcpConnectionPtr& con) {
        cout << con->toString() << " has connected!!!" << endl;
    }

    void onMessage(const TcpConnectionPtr& con) {
        // recv(sizeof(int)*2);
        // recv(length);

        string recv_string = con->receive();
        cout << "con->receive()= " << recv_string << endl;
        json json_recv = json::parse(recv_string);
        cli_msg msg_recv;
        cli_from_json(json_recv, msg_recv);

        // 处理msg_recv，把结果放在msg里
        string msg = msg_recv.data;
        // string msg = con->receive();

        // 处理msg
        // cout << ">>recv from client string = " << recv_string<< endl;
        cout << "msg to task" << msg << endl;
        // 需要将msg进行处理之后，再将其发送给客户端
        // 就需要做业务逻辑的处理，也就是处理msg

        MyTask task(msg, con, msg_recv.msgid);

        // 在执行了push操作，将task放在任务队列里面
        _pool.addTask(std::bind(&MyTask::process, task));
    }

    void onClose(const TcpConnectionPtr& con) {
        cout << con->toString() << " has closed!!!" << endl;
    }

   private:
    ThreadPool _pool;
    TcpServer _server;
};

#endif
